<?php

/**
 * 异常类\MonkeyException
 * @package    \
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\MonkeyException.php 版本号 2013-03-30 $
 */
final class MonkeyException extends Exception{
    private static $_error=array();
    private static $_title = array(
        1=> '致命错误(E_ERROR)',
        2 => '警告(E_WARNING)',
        4 => '语法解析错误(E_PARSE)',
        8 => '提示(E_NOTICE)',
        16 => 'E_CORE_ERROR',
        32 => 'E_CORE_WARNING',
        64 => '编译错误(E_COMPILE_ERROR)',
        128 => '编译警告(E_COMPILE_WARNING)',
        256 => '致命错误(E_USER_ERROR)',
        512 => '警告(E_USER_WARNING)',
        1024 => '提示(E_USER_NOTICE)',
        2047 => 'E_ALL',
        2048 => 'E_STRICT'
    );
    public function __construct($message,$code=0,$file=null,$line=null){
        parent::__construct($message,$code);
        $this->file= is_null($file)? parent::getFile() : $file;
        $this->line= is_null($line)? parent::getLine() : $line;
        $this->fillInfo();
    }
    public static function hasError(){
        return !empty(self::$_error);
    }
    public static function show404(){
        if(IS_AJAX) exit(json_encode(notice(false,'404_error，页面没有找到！')));
        include(FRAME. '/Debug/404.tpl.php');//载入404错误模板
        exit();
    }
    public static function show403(){
        if(IS_AJAX) exit(json_encode(notice(false,'403_denied，你无权访问！')));
        include(FRAME . '/Debug/403.tpl.php');//载入403错误模板
        exit();
    }
    public static function show($exit=true){
        DEBUG ? self::_debugShow() : self::_publicShow();
        if($exit) exit();
    }
    public static function halt($message,$code=0,$file=null,$line=null){
        try{
            throw new MonkeyException($message,$code,$file,$line);
        }catch (MonkeyException $e){
            $e->show();
        }
        return false;
    }
    private static function _debugShow(){
        $error_info=end(self::$_error);
        if(IS_AJAX){
            ob_clean();//清除之前输出的内容
            echo json_encode(notice(false,$error_info));
        }elseif(isset($_SERVER['REMOTE_ADDR'])){
            $error_info['goto_index']=__INDEX__==''?'/':__INDEX__;
            //载入显示模板
            require  FRAME. '/Debug/debug.tpl.php';
        }else{
            echo PHP_EOL,'程序运行出错：';
            foreach ($error_info as $key=>$value) echo PHP_EOL,$key,': ',$value;
        }
        exit;
    }
    private static function _publicShow(){
        $data=end(self::$_error);
        $error_info["title"]=$data["title"];
        $error_info["code"]=$data["code"];
        $error_info["log"]=$data["log"];
        if(IS_AJAX){
            $error_info["time"]=$data["time"];
            ob_clean();//清除之前输出的内容
            exit(notice(false,$error_info,'json'));
        }elseif(isset($_SERVER['REMOTE_ADDR'])){
            $error_info['goto_index']=__INDEX__==''?'/':__INDEX__;
            //载入显示模板
            require  FRAME. '/Debug/public.tpl.php';
        }else{
            echo PHP_EOL,'程序运行出错：';
            foreach ($error_info as $key=>$value) echo PHP_EOL,$key,': ',$value;
            echo PHP_EOL,'错误信息结束。';
        }
    }
    private function fillInfo() {
        $info=array();
        $info['title']= isset(self::$_title[$this->code])? self::$_title[$this->code] : '应用程序错误';
        $info['code']=$this->code;
        $current_path= oRouteManager()->getRoute();
        $info['path']= empty($current_path)?'路径为空，或者还没有开始解析路由。':$current_path;
        $info['ip'] = ip();
        $info['message']=$this->message;
        $info['file']=$this->file;
        $info['line']=$this->line;
        $lines=file($this->file);
        $info['source']=$lines[$this->line-1];
        $info['time']=date('Y-m-d H:i:s',TIME);
        $backtrace=debug_backtrace();
        $_code='';
        foreach ($backtrace as $key=>$value){
            $lines=file($value['file']);
            $backtrace[$key]['source']=trim($lines[$value['line']-1]);
            if(isset($backtrace[$key]['object'])) unset($backtrace[$key]['object']);
        }
        $info['backtrace']=print_r($backtrace, true);
        if(DEBUG){
            $info['log']='调试状态不记录日志。';
            self::$_error[]=$info;
            return;
        }
        error_reporting(0);
        //检查日志记录目录是否存在
        $log_dir=SYSTEM.'/logs';
        if(!dirCheck($log_dir)){
            $info['log']='不能创建日志文件，日志记录失败，请尽快通知管理员！';
            self::$_error[]=$info;
            error_reporting(DEBUG);
            return;
        }
        $log_file =$log_dir.'/'.date("Y-m-d",TIME).".log";
        //写入文件，记录错误信息
        $log_str='';
        foreach($info as $key => $value){
            $log_str.=PHP_EOL.$key.':'.$value;
        }
        if( error_log($log_str, 3, $log_file) ){
            $info['log']='我们已经对此错误做了详细的记录，我们将尽快处理你的问题！';
        }  else {
            $info['log']='日志记录失败，请尽快通知管理员！';
        }
        self::$_error[]=$info;
        error_reporting(DEBUG);
        return;
    }
}